﻿using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using StockholmsStad.Data.Interfaces;
using StockholmsStad.Runtime.Serialization.DataContract;
using StockholmsStad.Utilities.Exceptions;
using System;

namespace StockholmsStad.Data.Test
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class TestUnitCeremony : TestUnitBase
    {
        // before running each test 
        [TestInitialize()]
        public void MyTestInitialize()
        {
            BeginTransaction();
        }

        // after each test has run
        [TestCleanup()]
        public void MyTestCleanup()
        {
            EndTransaction();
        }

        [TestMethod]
        public void InsertANewLanguage()
        {
            ILanguageAgent agent = AgentFactory.GetLanguageAgent();

            int numOfLang = agent.GetLanguages(context).Count;
            int id = agent.AddLanguage(context, TestEntity.NewLanguage);

            Assert.AreNotEqual(0, id, "Språk kunde inte läggas till");

            var langs = agent.GetLanguages(context);
            int afterInsertNumOfLang = langs.Count;

            var foundLanguage = false;
            foreach (var lang in langs)
            {
                if(lang.Name == TestEntity.NewLanguage)
                    foundLanguage = true;
            }

            Assert.IsTrue(foundLanguage, "hittade inte tillagt språk");
            Assert.AreNotEqual(numOfLang, afterInsertNumOfLang, "Nytt språk kunde inte läggas till");
        }

        [TestMethod]
        public void InsertLanguageAndAddToCeremonyLanguageAndCertificateLanguage()
        {
            InsertANewLanguage();

            InsertCeremonyLanguage();

            InsertCertificateLanguage();
        }

        [TestMethod]
        public void IsSwedishLanguageDefault()
        {
            var agent = AgentFactory.GetLanguageAgent();
            var lang = agent.GetDefaultLanguage(context);

            Assert.AreEqual(TestEntity.ExistingLanguage, lang.Name, "Det förväntade språket är felaktigt");
        }

        private void InsertCeremonyLanguage()
        {
            var agent = AgentFactory.GetLanguageAgent();

            int defaultNoOfLanguages = agent.GetCeremonyLanguages(context).Count;

            agent.AddCeremonyLanguage(context, TestEntity.NewLanguage);

            int expectedNoOfLanguages = defaultNoOfLanguages + 1;
            int retrievedNoOfLanguages = agent.GetCeremonyLanguages(context).Count;

            Assert.AreEqual(expectedNoOfLanguages, retrievedNoOfLanguages,
                            string.Format("Expected no of languages {0} does not match retrived number {1}",
                                          expectedNoOfLanguages,
                                          retrievedNoOfLanguages));
        }

        private void InsertCertificateLanguage()
        {
            var agent = AgentFactory.GetLanguageAgent();

            int defaultNoOfLanguages = agent.GetCertificateLanguages(context).Count;

            agent.AddCertificateLanguage(context, TestEntity.NewLanguage);

            int expectedNoOfLanguages = defaultNoOfLanguages + 1;

            int retrievedNoOfLanguages = agent.GetCertificateLanguages(context).Count;

            Assert.AreEqual(expectedNoOfLanguages, retrievedNoOfLanguages,
                            string.Format("Expected no of languages {0} does not match retrived number {1}",
                                          expectedNoOfLanguages,
                                          retrievedNoOfLanguages));
        }

        [TestMethod]
        public void InsertSpecialNeedTest()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();

            int defaultNo = agent.GetSpecialNeeds(context).Count;

            var specialNeed = TestEntity.GetSpecialNeed();
            int specialNeedId = agent.AddSpecialNeed(context, specialNeed.Name);
            Assert.AreNotEqual(0, specialNeedId);
            int expectedNo = defaultNo + 1;

            int actualNo = agent.GetSpecialNeeds(context).Count;

            Assert.AreEqual(expectedNo, actualNo,
                            string.Format("Expected no of special needs {0} does not match retrived number {1}",
                                          expectedNo,
                                          actualNo));
        }

        [TestMethod]
        [ExpectedException(typeof(StockholmStadSystemException))]
        public void InsertSpecialNeedTest2()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();

            var specialNeed = TestEntity.GetSpecialNeed();
            int specialNeedId = agent.AddSpecialNeed(context, specialNeed.Name);
            Assert.AreNotEqual(0, specialNeedId);
            // Nästa insert ska kasta exception
            specialNeedId = agent.AddSpecialNeed(context, specialNeed.Name);
        }

        [TestMethod]
        [ExpectedException(typeof (StockholmStadSystemException))]
        public void InsertCeremonyLanguageThatDoesNotExist()
        {
            const string languageName = "LanguageNotExist";
            var agent = AgentFactory.GetLanguageAgent();
            agent.AddCeremonyLanguage(context, languageName);
        }

        [TestMethod]
        [ExpectedException(typeof (StockholmStadSystemException))]
        public void InsertCertificateLanguageThatDoesNotExist()
        {
            const string languageName = "LanguageNotExist";
            var agent = AgentFactory.GetLanguageAgent();
            agent.AddCertificateLanguage(context, languageName);
        }

        [TestMethod]
        public void InsertRetrieveCeremony()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();

            var languageAgent = AgentFactory.GetLanguageAgent();
            var langId = languageAgent.AddLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, langId, "Inget nytt språk skapades");

            var cerLangId = languageAgent.AddCeremonyLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, cerLangId, "Inget nytt ceremoni språk skapades");

            var certLangId = languageAgent.AddCertificateLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, certLangId, "Inget nytt certifikat språk skapades");

            Ceremony ceremony = TestEntity.GetNewCeremony();
            ceremony.CeremonyLanguage.Id = cerLangId;
            ceremony.CertificateLanguage.Id = certLangId;

            int ceremonyId = agent.AddCeremony(context, ceremony);
            Assert.AreNotEqual(0, ceremonyId, "Ceremony was not inserted");

            Ceremony retrievedCeremony = agent.GetCeremony(context, ceremonyId);

            AreCeremonyEqual(ceremony, retrievedCeremony);
        }

        [TestMethod]
        public void InsertUpdateAndRetrieveCeremony()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();

            var languageAgent = AgentFactory.GetLanguageAgent();
            var langId = languageAgent.AddLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, langId, "Inget nytt språk skapades");

            var cerLangId = languageAgent.AddCeremonyLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, cerLangId, "Inget nytt ceremoni språk skapades");

            var certLangId = languageAgent.AddCertificateLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, certLangId, "Inget nytt certifikat språk skapades");

            Ceremony ceremony = TestEntity.GetNewCeremony();
            ceremony.CeremonyLanguage.Id = cerLangId;
            ceremony.CertificateLanguage.Id = certLangId;

            int ceremonyId = agent.AddCeremony(context, ceremony);
            Assert.AreNotEqual(0, ceremonyId, "Ceremony was not inserted");

            Ceremony retrievedCeremony = agent.GetCeremony(context, ceremonyId);

            AreCeremonyEqual(ceremony, retrievedCeremony);

            ceremony.Interpreter = true;
            ceremony.Note = "";

            agent.UpdateCeremony(context, ceremonyId, ceremony);
            Ceremony updatedCeremony = agent.GetCeremony(context, ceremonyId);

            AreCeremonyEqual(ceremony, updatedCeremony);
        }

        [TestMethod]
        public void InsertUpdateAndRetrieveCeremonyWithBookingInfo()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();

            var languageAgent = AgentFactory.GetLanguageAgent();
            var langId = languageAgent.AddLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, langId, "Inget nytt språk skapades");

            var cerLangId = languageAgent.AddCeremonyLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, cerLangId, "Inget nytt ceremoni språk skapades");

            var certLangId = languageAgent.AddCertificateLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, certLangId, "Inget nytt certifikat språk skapades");

            var ceremony = TestEntity.GetNewCeremony();
            ceremony.CeremonyLanguage.Id = cerLangId;
            ceremony.CertificateLanguage.Id = certLangId;
            
            var ceremonyId = agent.AddCeremony(context, ceremony);
            Assert.AreNotEqual(0, ceremonyId, "Ceremony was not inserted");

            var retrievedCeremony = agent.GetCeremony(context, ceremonyId);
            AreCeremonyEqual(ceremony, retrievedCeremony);

            var couple = TestEntity.GetNewCoupleWithContact();
            var ticketAgent = AgentFactory.GetTicketAgent();

            var ticketId = ticketAgent.CreateTicket(context, couple, ceremony);
            Assert.AreNotEqual(0, ticketId, "Inget ärende skapades");

            var timeblock = TestEntity.GetNewTimeBlock();
            var maintenanceAgent = AgentFactory.GetMaintenanceAgent();
            var timeblockId = maintenanceAgent.AddTimeBlock(context, timeblock);
            Assert.AreNotEqual(0, timeblockId, "Inget tidsblock lades till");
            
            var booking = TestEntity.GetOrdinaryBooking();
            booking.DateTime.TimeBlockId = timeblockId;

            var bookingAgent = AgentFactory.GetBookingAgent();
            bookingAgent.AddBooking(context, ticketId, booking, null);

            // Uppdatera ceremoniinformationen
            ceremony.ImpedimentDocAllowDelayDays = 0;
            ceremony.ImpedimentDocIssuedDate = TestEntity.GetImpedimentDocIssuedDate;
            agent.UpdateCeremonyBookingDetails(context, ceremonyId, ceremony, booking);

            agent.UpdateCeremony(context, ceremonyId, ceremony);
            Ceremony updatedCeremony = agent.GetCeremony(context, ceremonyId);

            AreCeremonyEqual(ceremony, updatedCeremony);
        }



        public void RemoveCeremonyLanguage()
        {
            var agent = AgentFactory.GetLanguageAgent();

            var defaultNoOfLanguages = agent.GetCeremonyLanguages(context).Count;
            agent.DeleteCeremonyLanguage(context, TestEntity.GetNewCeremonyLanguage());

            var expected = defaultNoOfLanguages - 1;
            var retrievedNoOfLanguages = agent.GetCeremonyLanguages(context).Count;
            Assert.AreEqual(expected, retrievedNoOfLanguages,
                string.Format("Expected no of languages {0} does not match retrived number {1}",
                expected, retrievedNoOfLanguages));
        }

        [TestMethod]
        public void RemoveCertificateLanguage()
        {

            var agent = AgentFactory.GetLanguageAgent();
            var language = TestEntity.GetNewCertificateLanguage();
            language.Id = agent.AddCertificateLanguage(context, language.Name);
            var defaultNoOfLanguages = agent.GetCertificateLanguages(context).Count;
            agent.DeleteCertificateLanguage(context, language);

            var expected = defaultNoOfLanguages - 1;
            var retrievedNoOfLanguages = agent.GetCertificateLanguages(context).Count;
            Assert.AreEqual(expected, retrievedNoOfLanguages,
                string.Format("Expected no of languages {0} does not match retrived number {1}",
                expected, retrievedNoOfLanguages));
        }

        public static void AreCeremonyEqual(Ceremony expected, Ceremony retrieved)
        {
            Assert.AreEqual(expected.CeremonyLanguage.Id, retrieved.CeremonyLanguage.Id,
                            string.Format("Expected ceremony language id ({0}) differs from recieved ({1})",
                                          expected.CeremonyLanguage, retrieved.CeremonyLanguage));
            Assert.AreEqual(expected.CertificateLanguage.Id, retrieved.CertificateLanguage.Id,
                            string.Format("Expected certificate language id ({0}) differs from recieved ({1})",
                                          expected.CertificateLanguage, retrieved.CertificateLanguage));

            Assert.AreEqual(expected.CeremonyLanguage.Name, retrieved.CeremonyLanguage.Name,
                            string.Format("Expected ceremony language Name ({0}) differs from recieved ({1})",
                                          expected.CeremonyLanguage, retrieved.CeremonyLanguage));
            Assert.AreEqual(expected.CertificateLanguage.Name, retrieved.CertificateLanguage.Name,
                            string.Format("Expected certificate language Name ({0}) differs from recieved ({1})",
                                          expected.CertificateLanguage, retrieved.CertificateLanguage));

            if (expected.SpecialNeeds != null && retrieved.SpecialNeeds != null)
            {
                Assert.AreEqual(expected.SpecialNeeds.Count, retrieved.SpecialNeeds.Count);
                for (int i = 0; i < expected.SpecialNeeds.Count; i++)
                {
                    Assert.AreEqual(expected.SpecialNeeds[i].Name, retrieved.SpecialNeeds[i].Name,
                                    string.Format("Expected needs name ({0}) differs from recieved ({1})",
                                                  expected.SpecialNeeds[i].Name, retrieved.SpecialNeeds[i].Name));
                    Assert.AreEqual(expected.SpecialNeeds[i].Id, retrieved.SpecialNeeds[i].Id,
                                    string.Format("Expected needs id ({0}) differs from recieved ({1})",
                                                  expected.SpecialNeeds[i].Id, retrieved.SpecialNeeds[i].Id));
                }
            }

            Assert.AreEqual(expected.Note, retrieved.Note, 
                string.Format("notering matchar inte. Förväntat: {0}, Erhållet: {1}", expected.Note, retrieved.Note));
            Assert.AreEqual(expected.Interpreter, retrieved.Interpreter);
            Assert.AreEqual(expected.ImpedimentDocAllowDelayDays, retrieved.ImpedimentDocAllowDelayDays, "HP latest stämmer inte överens");
            Assert.AreEqual(expected.ImpedimentDocEarliestDate, retrieved.ImpedimentDocEarliestDate, "HP tidigast stämmer inte överens");
            Assert.AreEqual(expected.ImpedimentDocIssuedDate, retrieved.ImpedimentDocIssuedDate, "HP issued date stämmer inte överens");
            Assert.AreEqual(expected.ImpedimentDocLatestDate, retrieved.ImpedimentDocLatestDate, "HP latest date stämmer inte överens");
        }

        /// <summary>
        /// Add special need
        /// </summary>
        [TestMethod]
        public void InsertRetrieveCeremony2()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            Ceremony ceremony = TestEntity.GetNewCeremony();

            var languageAgent = AgentFactory.GetLanguageAgent();
            var langId = languageAgent.AddLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, langId, "Inget nytt språk skapades");

            var cerLangId = languageAgent.AddCeremonyLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, cerLangId, "Inget nytt ceremoni språk skapades");

            var certLangId = languageAgent.AddCertificateLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, certLangId, "Inget nytt certifikat språk skapades");

            ceremony.CeremonyLanguage.Id = cerLangId;
            ceremony.CertificateLanguage.Id = certLangId;

            var specialNeed = TestEntity.GetSpecialNeed();
            var needId = agent.AddSpecialNeed(context, specialNeed.Name);

            Assert.AreNotEqual(0, needId, "Inget hjälpmedel lades till");
            specialNeed.Id = needId;

            ceremony.SpecialNeeds = new List<ValueIdPair> {specialNeed};
            int ceremonyId = agent.AddCeremony(context, ceremony);

            Assert.AreNotEqual(0, ceremonyId, "Ceremony was not inserted");

            Ceremony retrievedCeremony = agent.GetCeremony(context, ceremonyId);

            AreCeremonyEqual(ceremony, retrievedCeremony);
        }

        /// <summary>
        /// Add more special needs
        /// </summary>
        [TestMethod]
        public void InsertRetrieveCeremony3()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();

            var specialNeed = TestEntity.GetSpecialNeed1();
            var needId = agent.AddSpecialNeed(context, specialNeed.Name);

            Assert.AreNotEqual(0, needId, "Inget hjälpmedel lades till");
            specialNeed.Id = needId;

            Ceremony ceremony = TestEntity.GetNewCeremony();


            var languageAgent = AgentFactory.GetLanguageAgent();
            var langId = languageAgent.AddLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, langId, "Inget nytt språk skapades");

            var cerLangId = languageAgent.AddCeremonyLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, cerLangId, "Inget nytt ceremoni språk skapades");

            var certLangId = languageAgent.AddCertificateLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, certLangId, "Inget nytt certifikat språk skapades");

            ceremony.CeremonyLanguage.Id = cerLangId;
            ceremony.CertificateLanguage.Id = certLangId;

            ceremony.SpecialNeeds = new List<ValueIdPair> { specialNeed };
            int ceremonyId = agent.AddCeremony(context, ceremony);

            Assert.AreNotEqual(0, ceremonyId, "Ceremony was not inserted");

            Ceremony retrievedCeremony = agent.GetCeremony(context, ceremonyId);

            AreCeremonyEqual(ceremony, retrievedCeremony);
        }

        /// <summary>
        /// With more special needs
        /// </summary>
        [TestMethod]
        public void RemoveCeremony()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();

            var specialNeed = TestEntity.GetSpecialNeed1();
            var needId = agent.AddSpecialNeed(context, specialNeed.Name);

            Assert.AreNotEqual(0, needId, "Inget hjälpmedel lades till");
            specialNeed.Id = needId;
            
            Ceremony ceremony = TestEntity.GetNewCeremony();

            var languageAgent = AgentFactory.GetLanguageAgent();
            var langId = languageAgent.AddLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, langId, "Inget nytt språk skapades");

            var cerLangId = languageAgent.AddCeremonyLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, cerLangId, "Inget nytt ceremoni språk skapades");

            var certLangId = languageAgent.AddCertificateLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, certLangId, "Inget nytt certifikat språk skapades");

            ceremony.CeremonyLanguage.Id = cerLangId;
            ceremony.CertificateLanguage.Id = certLangId;

            ceremony.SpecialNeeds = new List<ValueIdPair> { specialNeed };
            int ceremonyId = agent.AddCeremony(context, ceremony);

            Assert.AreNotEqual(0, ceremonyId, "Ceremony was not inserted");

            Ceremony retrievedCeremony = agent.GetCeremony(context, ceremonyId);
            AreCeremonyEqual(ceremony, retrievedCeremony);

            agent.DeleteCeremony(context, ceremonyId);
            Ceremony deletedCeremony = agent.GetCeremony(context, ceremonyId);
            Assert.IsNull(deletedCeremony);
        }

        /// <summary>
        /// With more special needs
        /// </summary>
        [TestMethod]
        public void UpdateCeremony()
        {
            ITicketAgent ticketAgent = AgentFactory.GetTicketAgent();
            ICeremonyAgent ceremonyAgent = AgentFactory.GetCeremonyAgent();

            Couple couple = TestEntity.GetNewCoupleWithoutContact();
            var specialNeed = TestEntity.GetSpecialNeed1();
            var needId = ceremonyAgent.AddSpecialNeed(context, specialNeed.Name);

            Assert.AreNotEqual(0, needId, "Inget hjälpmedel lades till");
            specialNeed.Id = needId;

            Ceremony ceremony = TestEntity.GetNewCeremony();
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();

            var languageAgent = AgentFactory.GetLanguageAgent();
            var langId = languageAgent.AddLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, langId, "Inget nytt språk skapades");

            var cerLangId = languageAgent.AddCeremonyLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, cerLangId, "Inget nytt ceremoni språk skapades");

            var certLangId = languageAgent.AddCertificateLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, certLangId, "Inget nytt certifikat språk skapades");

            ceremony.CeremonyLanguage.Id = cerLangId;
            ceremony.CertificateLanguage.Id = certLangId;

            ceremony.SpecialNeeds = new List<ValueIdPair> { specialNeed };

            int ticketId = ticketAgent.CreateTicket(context, couple, ceremony);
            Assert.AreNotEqual(0, ticketId, "Inget ärende skapades");

            Ticket ticket = ticketAgent.GetTicket(context, ticketId);

            // Assign added id´s
            couple.CoupleId = ticket.Couple.CoupleId;
            couple.Person1.PersonId = ticket.Couple.Person1.PersonId;
            couple.Person2.PersonId = ticket.Couple.Person2.PersonId;

            TestUnitPerson.ArePersonEqual(couple.Person1, ticket.Couple.Person1);
            TestUnitPerson.ArePersonEqual(couple.Person2, ticket.Couple.Person2);

            int ceremonyId = ceremonyAgent.GetCeremonyId(context, ticket.TicketId);
            Ceremony retrievedCeremony = ceremonyAgent.GetCeremony(context, ceremonyId);

            AreCeremonyEqual(ceremony, retrievedCeremony);
            Assert.AreEqual(retrievedCeremony.SpecialNeeds.Count, ceremony.SpecialNeeds.Count);
            ceremony.CeremonyLanguage = new ValueIdPair {Name = "Engelska"};
            ceremony.CertificateLanguage = new ValueIdPair { Name = "Engelska" };
            ceremony.Interpreter = true;
            int numOfNeeds = ceremony.SpecialNeeds.Count;

            var addedSpecialNeed = TestEntity.GetSpecialNeed2();
            var addedNeedId = ceremonyAgent.AddSpecialNeed(context, addedSpecialNeed.Name);

            Assert.AreNotEqual(0, addedNeedId, "Inget hjälpmedel lades till");
            addedSpecialNeed.Id = addedNeedId;

            ceremony.SpecialNeeds.Add(addedSpecialNeed);

            ceremonyAgent.UpdateCeremony(context, ceremonyId, ceremony);
            
            Ceremony updatedCeremony = ceremonyAgent.GetCeremony(context, ceremonyId);
            // A little bit ugly, but this is just for testing...
            ceremony.CeremonyLanguage.Id = updatedCeremony.CeremonyLanguage.Id;
            ceremony.CertificateLanguage.Id = updatedCeremony.CertificateLanguage.Id;

            AreCeremonyEqual(ceremony, updatedCeremony);

            Assert.AreEqual(numOfNeeds + 1, updatedCeremony.SpecialNeeds.Count);
            ceremony.SpecialNeeds = new List<ValueIdPair>();

            ceremonyAgent.UpdateCeremony(context, ceremonyId, ceremony);
            updatedCeremony = ceremonyAgent.GetCeremony(context, ceremonyId);
            AreCeremonyEqual(ceremony, updatedCeremony);

            Assert.AreEqual(updatedCeremony.SpecialNeeds, updatedCeremony.SpecialNeeds);
        }
    }
}